package com.formina.stars;

import java.util.HashMap;
import java.util.Random;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import com.formina.engine.Engine;
import com.formina.engine.GameRenderer;
import com.formina.engine.ModelInfo;
import com.formina.engine.ObjReader;
import com.formina.engine.Pointer;
import com.formina.stars.Confetti;
import com.formina.stars.R;
import com.formina.stars.Star;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;
import android.util.Log;
import android.view.MotionEvent;


public class StarRenderer extends GameRenderer {
	
	
    
    //GAME ONLY
    private final float curScale = 0.1f;
    
    public static final int MODE_NONE = 0;
    public static final int MODE_ADDING=1;
    public static final int MODE_DESTROY=2;
    public static final int MODE_FINGER_UP = 3;
    
    //audio
    AudioManager mgr;
    float streamVolumeCurrent;
    float streamVolumeMax;   
    float volume;
    
    //comets
    final int maxComets = 4;
    
    //
	public StarRenderer(){
		
	}
	
	private Star lastStar = null;
	
	
	public void HandleTouch(Pointer po){
		/*
		final int aid = ev.getActionIndex();
		final int action = ev.getAction();
		final int actionCode = action & MotionEvent.ACTION_MASK;
		Pointer ap;
		ap = Engine.GetPointer(ev.getPointerId(aid));
		if(actionCode == MotionEvent.ACTION_UP || actionCode==MotionEvent.ACTION_POINTER_UP){
			ap.Mode=StarRenderer.MODE_FINGER_UP;
		}else{
			if(ap.Mode==StarRenderer.MODE_FINGER_UP){
				ap.Mode=StarRenderer.MODE_NONE;
			}
		}
		*/

		//for(int i=0;i<ev.getPointerCount();i++){
			//po.x = ev.getX(i);
			//po.y = ev.getY(i);
			
			switch(po.Mode){
			case MODE_NONE: //no mode yet
				Destroy(po);
				if(po.Mode==MODE_NONE){
					Adding(po);
				}
				break;
			case MODE_ADDING: //adding
				this.Adding(po);
				break;
			case MODE_DESTROY: //destroying
				this.Destroy(po);
				break;
			case MODE_FINGER_UP: //finger up
				po.Inc = 0;
				break;
			}
		//}
		
	}
	
	private boolean Adding(Pointer p){
		
		float size = .55f;
		float tempsize = size + (p.Inc  * curScale);
		
		Star s = new Star(new float[]{p.x, p.y, 0f},new float[]{tempsize,tempsize,tempsize});
		s.setZ(tempsize+s.Width());
		
		if(p.LastStar!=null){
			if(p.LastStar.CheckTQCollision(s)){
				return false; //collided do nothing
			}
		}
		p.Mode = MODE_ADDING;
		size = tempsize;
		Models.add(s);
		p.LastStar = s;
		p.Inc++;
		this.playSound(0);
		
		return true;
	}
	
	private boolean Destroy(Pointer p){
		for(int i= Models.size()-1; i>=0;i--){
			if (Models.get(i).CheckTouch(p.x,p.y)){
				p.Mode = MODE_DESTROY;
				Effects.add(new Confetti(Models.get(i).Location(), Models.get(i).Scale()));
				Models.remove(i);
				Random rand = new Random();
				int sound =-1;
				sound = rand.nextInt(2);
				this.playSound(sound+2);
				return true;
			}
		}
		return false;
	}
	
	long fps = 0;
	
	@Override
	public void onDrawFrame(GL10 gl) {
		loopStart = System.currentTimeMillis();
		
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
	    gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	    gl.glShadeModel(GL10.GL_SMOOTH);
		gl.glLoadIdentity();
		
		DrawModels(gl);

		//fps stuff
		/*
		loopEnd = System.currentTimeMillis();
	    loopRunTime = ((loopEnd - loopStart));
	    fps = loopRunTime / 1000;
	    Log.d("FPS", String.valueOf(loopRunTime));
	    */
		//Log.d("STATS", String.valueOf(Models.size() + " | " + Effects.size()));
		loopEnd = System.currentTimeMillis();
	    loopRunTime = ((loopEnd - loopStart));
	    try {
            if (loopRunTime < Engine.GAME_THREAD_FPS_SLEEP){
                    Thread.sleep(Engine.GAME_THREAD_FPS_SLEEP - loopRunTime);
            }
	    } catch (InterruptedException e) {
            // TODO Auto-generated catch block
	    	e.printStackTrace();
	    }
	}
	
	int comets = 0;
	void MakeComets(GL10 gl){
		Random rand = new Random();
		//if(comets < this.maxComets){
			if(rand.nextInt(1000)<5){
				Comet comet = new Comet();
				float tempscale = 75f;
				float x, y, z;
				z = 0f;
				//figure out staring point
				//get random number to decide
				//which side to start from
				//0 top, 1 bottom, 2 left, 3 right
				int side = rand.nextInt(4);
				switch(side){
				case 0:	//top
					y = 0;
					x = rand.nextInt((int)Width);
					comet = new Comet(new float[]{x,y,z},new float[]{tempscale,tempscale,0f});
					comet.setDirection(90 + rand.nextInt(180));
					break;
				case 1: //bottom
					y = Height;
					x = rand.nextInt((int)Width);
					comet = new Comet(new float[]{x,y,z},new float[]{tempscale,tempscale,0f});
					float angle = 270 + rand.nextInt(180);
					if(angle > 360){
						angle-=360;
					}
					comet.setDirection(angle);
					break;
				case 2: //left
					y = rand.nextInt((int)Height);
					x = 0f;
					comet = new Comet(new float[]{x,y,z},new float[]{tempscale,tempscale,0f});
					comet.setDirection(0 + rand.nextInt(180));
					break;
				case 3:
					y = rand.nextInt((int)Height);
					x = Width;
					comet = new Comet(new float[]{x,y,z},new float[]{tempscale,tempscale,0f});
					comet.setDirection(180 + rand.nextInt(180));
					break;
				default:
					break;
				}
				Effects.add(comet);
				comets++;
			}
		//}
		
	}
	
	void DrawModels(GL10 gl){
		
		if(Models.size() > 0 ){
			
			for(int x= Models.size()-1; x>=0;x--){
				Models.get(x).update(loopStart);
				if(Models.get(x).IsDead()){
					Models.remove(x);
				}
			}
			
			Lighting(gl);
			
			for(int x= 0; x < Models.size();x++){
				Models.get(x).draw(gl);
			}
			gl.glDisable(GL10.GL_LIGHTING);

			//gl.glTranslatef(0, 0, 0);
		}
		MakeComets(gl);

		if(Effects.size() >0){
			
			for(int x= Effects.size()-1; x>=0;x--){
				Effects.get(x).update(loopStart);
				if(Effects.get(x).IsDead()){
					Effects.remove(x);
				}
			}
			for(int x= Effects.size()-1; x>=0;x--){
				Effects.get(x).draw(gl);
				
			}
		}
		
	}
	
	public void playSound(int sound) {
		new SoundPlayer(sound);
	    //soundPool.play(soundPoolMap.get(sound), volume, volume, 1, 0, 1f);

	}
	
	public void setColor(int r, int g, int b, boolean useRandom){
		Engine.UseRandomColors = useRandom;
		Engine.DefaultColor = new float[]{(float)r/255f,(float)g/255f,(float)b/255f,1f};
	}
	
	void Lighting(GL10 gl){
		gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glEnable(GL10.GL_LIGHTING);
		gl.glEnable(GL10.GL_LIGHT0);
		gl.glShadeModel(GL10.GL_SMOOTH);
		float ambient[] ={ 1.0f, 1.0f, 1.0f,1f};
		float direction[] ={ 1f,1f,1f,1f };

		//gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_LIGHT_MODEL_AMBIENT, ambient,0);
		gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, ambient,0);
		//gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, diffuse,0);
		//gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, specular,0);
		gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, direction,0);

		
		    
	}
	
	float Width,Height;
	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		// TODO Auto-generated method stub
		Height=height;Width=width;
		Engine.HEIGHT = height; Engine.WIDTH = width;
		gl.glViewport(0, 0, width,height);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		
		//GLU.gluPerspective(gl, 45.0f, (float) width / height, .1f, 100.f);
		gl.glOrthof(0, (float)width, (float)height, 0,-1000f,1000f);
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		//enable blending

	    gl.glLoadIdentity();
	    
	    
	}
	
	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		// TODO Auto-generated method stub
		soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
	    soundPoolMap = new HashMap<Integer, Integer>();
	    soundPoolMap.put(0, soundPool.load(Engine.CONTEXT, R.raw.jump, 1));
	    soundPoolMap.put(1, soundPool.load(Engine.CONTEXT, R.raw.popup, 1));
	    soundPoolMap.put(2, soundPool.load(Engine.CONTEXT, R.raw.fireworks, 1));
	    soundPoolMap.put(3, soundPool.load(Engine.CONTEXT, R.raw.firework2, 1));
	    mgr = (AudioManager)Engine.CONTEXT.getSystemService(Context.AUDIO_SERVICE);
	    streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_MUSIC);
	    streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);    
	    volume = streamVolumeCurrent / streamVolumeMax;
	    
		gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		gl.glClearDepthf(1.0f);
		  gl.glShadeModel(GL10.GL_FLAT);
		  gl.glDepthFunc(GL10.GL_LEQUAL);
		  gl.glFrontFace(GL10.GL_CCW);
		  gl.glCullFace(GL10.GL_BACK);
		  gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

		  gl.glDisable(GL10.GL_DITHER);
		  
		  gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  
		  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

		  gl.glEnable(GL10.GL_BLEND);
		  gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		
		    
		  Engine.Star = ObjReader.ReadObj("3dStar.obj");
		  Engine.StarParticle = ObjReader.ReadObj("star.obj");	
		  Engine.Star.Bind();
		  Engine.StarParticle.Bind();
		  Engine.Comet = ObjReader.Plane(32f);
		  Engine.Comet.Bind();
		  ModelInfo.loadTexture(gl, R.drawable.comet, Engine.CONTEXT);
		  
			
		  Engine.Comet.Bind();
		    /*
	        star1 = new Star(new float[]{200f,200f,0},new float[]{1f,1f,1f});	
	        star2 = new Star(new float[]{400f,200f,0},new float[]{1f,1f,1f});		
	        star2.setRotation(new float[]{0,45f,0});
	        star3 = new Star(new float[]{600f,200f,0},new float[]{1f,1f,1f});		
	        star3.setRotation(new float[]{0,23f,0});
		     */

	}
	
	class SoundPlayer implements Runnable{
		int soundId;
		public SoundPlayer(int soundId){
			this.soundId  = soundId;
			this.run();
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
		    soundPool.play(soundPoolMap.get(soundId), volume, volume, 1, 0, 1f);
		    try {
				super.finalize();
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	
}
	

